convert garmin gpi to Format class (#849)
authortsteven4 <13596209+tsteven4@users.noreply.github.com>
Mon, 7 Feb 2022 14:10:14 +0000 (07:10 -0700)
committerGitHub <noreply@github.com>
Mon, 7 Feb 2022 14:10:14 +0000 (07:10 -0700)
* convert garmin_gpi to Format class

* const member funcs

* flush out includes

garmin_gpi.cc
garmin_gpi.h
vecs.h

index 74fc07b333a6491fb5e67f452ce1e8d850159093..36d1aca91cb9418f7e5b8679a9c5daaaa24e2029 100644 (file)
        * support category from GMSD "Garmin Special Data"
 */
 
-#include <algorithm>               // for stable_sort
-#include <cctype>                  // for tolower
-#include <cstdint>                 // for int32_t, int16_t, uint16_t
-#include <cstdio>                  // for SEEK_CUR, SEEK_SET
-#include <cstdlib>                 // for atoi
-#include <cstring>                 // for strlen, strncmp
-#include <ctime>                   // for time, time_t, gmtime
+#include "garmin_gpi.h"
 
 #include <QByteArray>              // for QByteArray, operator==
-#include <QList>                   // for QList<>::iterator, QList
+#include <QList>                   // for QList
 #include <QString>                 // for QString, operator+, operator<
 #include <QThread>                 // for QThread
-#include <QVector>                 // for QVector
 #include <Qt>                      // for CaseInsensitive
 #include <QtGlobal>                // for foreach, Q_UNUSED
 
-#include "defs.h"
-#include "garmin_gpi.h"
+#include <algorithm>               // for stable_sort
+#include <cctype>                  // for tolower
+#include <cstdint>                 // for uint32_t, int32_t
+#include <cstdio>                  // for SEEK_CUR, SEEK_SET
+#include <cstdlib>                 // for atoi
+#include <cstring>                 // for strlen, strncmp
+#include <ctime>                   // for time, gmtime, time_t, tm
+#include <memory>                  // for unique_ptr
+
+#include "defs.h"                  // for Waypoint, fatal, STRFROMUNICODE, le_write32, le_write16, wp_flags, warning, bounds, KPH_TO_MPS, MPH_TO_MPS, WAYPT_HAS, gpsbabel_testmode, parse_speed, WAYPT_SET, MILES_TO_METERS, MPS_TO_KPH, MPS_TO_MPH, mkgmtime, mkshort, mkshort_del_handle, mkshort_new_...
 #include "cet_util.h"              // for cet_convert_init
 #include "formspec.h"              // for FormatSpecificDataList
 #include "garmin_fs.h"             // for garmin_fs_t, garmin_fs_alloc
-#include "gbfile.h"                // for gbfputint32, gbfgetint32, gbfgetint16, gbfputint16, gbfgetc, gbfputc, gbfread, gbftell, gbfwrite, gbfseek, gbfclose, gbfopen_le, gbfgetuint16, gbfile, gbsize_t
+#include "gbfile.h"                // for gbfputint32, gbfgetint32, gbfgetint16, gbfputint16, gbfgetc, gbfputc, gbfread, gbftell, gbfwrite, gbfseek, gbfclose, gbfopen_le, gbfgetuint16, gbsize_t, gbfile
 #include "jeeps/gpsmath.h"         // for GPS_Math_Deg_To_Semi, GPS_Math_Semi_To_Deg
 
 
 #define GPI_ADDR_POSTAL_CODE   8
 #define GPI_ADDR_ADDR          16
 
-static char* opt_cat, *opt_pos, *opt_notes, *opt_hide_bitmap, *opt_descr, *opt_bitmap;
-static char* opt_unique, *opt_alerts, *opt_units, *opt_speed, *opt_proximity, *opt_sleep;
-static char* opt_lang;
-static char* opt_writecodec;
-static double defspeed, defproximity;
-static int alerts;
-
-static QVector<arglist_t> garmin_gpi_args = {
-  {
-    "alerts", &opt_alerts, "Enable alerts on speed or proximity distance",
-    nullptr, ARGTYPE_BOOL, ARG_NOMINMAX, nullptr
-  },
-  {
-    "bitmap", &opt_bitmap, "Use specified bitmap on output",
-    nullptr, ARGTYPE_FILE, ARG_NOMINMAX, nullptr
-  },
-  {
-    "category", &opt_cat, "Default category on output",
-    "My points", ARGTYPE_STRING, ARG_NOMINMAX, nullptr
-  },
-  {
-    "hide", &opt_hide_bitmap, "Don't show gpi bitmap on device",
-    nullptr, ARGTYPE_BOOL, ARG_NOMINMAX, nullptr
-  },
-  {
-    "descr", &opt_descr, "Write description to address field",
-    nullptr, ARGTYPE_BOOL, ARG_NOMINMAX, nullptr
-  },
-  {
-    "notes", &opt_notes, "Write notes to address field",
-    nullptr, ARGTYPE_BOOL, ARG_NOMINMAX, nullptr
-  },
-  {
-    "position", &opt_pos, "Write position to address field",
-    nullptr, ARGTYPE_BOOL, ARG_NOMINMAX, nullptr
-  },
-  {
-    "proximity", &opt_proximity, "Default proximity",
-    nullptr, ARGTYPE_STRING, ARG_NOMINMAX, nullptr
-  },
-  {
-    "sleep", &opt_sleep, "After output job done sleep n second(s)",
-    nullptr, ARGTYPE_INT, "1", nullptr, nullptr
-  },
-  {
-    "speed", &opt_speed, "Default speed",
-    nullptr, ARGTYPE_STRING, ARG_NOMINMAX, nullptr
-  },
-  {
-    "unique", &opt_unique, "Create unique waypoint names (default = yes)",
-    "Y", ARGTYPE_BOOL, ARG_NOMINMAX, nullptr
-  },
-  {
-    "units", &opt_units, "Units used for names with @speed ('s'tatute or 'm'etric)",
-    "m", ARGTYPE_STRING, ARG_NOMINMAX, nullptr
-  },
-  {
-    "writecodec", &opt_writecodec, "codec to use for writing strings",
-    "windows-1252", ARGTYPE_STRING, ARG_NOMINMAX, nullptr
-  },
-  {
-    "languagecode", &opt_lang, "language code to use for reading dual language files",
-    nullptr, ARGTYPE_STRING, ARG_NOMINMAX, nullptr
-  },
-};
-
-struct reader_data_t {
-public:
-  int D2;
-  char S3[9];          /* "GRMRECnn" */
-  time_t crdate;       /* creation date and time */
-  char POI[4];         /* "POI" */
-  char S8[3];
-  QString group;
-  QString category;
-};
-
-struct writer_data_t {
-  QList<Waypoint*> waypt_list;
-  int sz{0};
-  int alert{0};
-  bounds bds;
-  writer_data_t* top_left{nullptr};
-  writer_data_t* top_right{nullptr};
-  writer_data_t* bottom_left{nullptr};
-  writer_data_t* bottom_right{nullptr};
-};
-
-struct gpi_waypt_data_t {
-  int sz;
-  char* addr;
-  char* postal_code;
-};
-
-struct bmp_header_t {
-  int32_t size;
-  int16_t res1;
-  int16_t res2;
-  int32_t image_offset;
-  int32_t header_size;
-  int32_t width;
-  int32_t height;
-  int16_t planes;
-  int16_t bpp;
-  int32_t compression_type;
-  int32_t image_data_size;
-  int32_t resolution_h;
-  int32_t resolution_v;
-  int32_t used_colors;
-  int32_t important_colors;
-};
-
-struct gpi_bitmap_header_t {
-  int16_t index;
-  int16_t height;
-  int16_t width;
-  int16_t line_sz;
-  int16_t bpp;
-  int16_t fixed_0;
-  int32_t image_size;
-  int32_t fixed_2c;
-  int32_t palette_size;
-  int32_t tr_color;
-  int32_t flag2;
-  int32_t size_2c;
-};
-
-struct gpi_waypt_t {
-  int sz{0};
-  int alerts{0};
-  short mask{0};
-  QString addr;
-  QString city;
-  QString country;
-  QString phone_nr;
-  QString postal_code;
-  QString state;
-};
-
-static gbfile* fin, *fout;
-static uint16_t codepage;      /* code-page, e.g. 1252, 65001 */
-static reader_data_t* rdata;
-static writer_data_t* wdata;
-static short_handle short_h;
-static char units;
-static time_t gpi_timestamp = 0;
+#define GPI_BITMAP_SIZE sizeof(gpi_bitmap)
 
 #ifdef GPI_DBG
 # define PP warning("@%1$6x (%1$8d): ", gbftell(fin))
@@ -243,8 +99,8 @@ static time_t gpi_timestamp = 0;
 *******************************************************************************/
 
 /* look for or initialize GMSD */
-static garmin_fs_t*
-gpi_gmsd_init(Waypoint* wpt)
+garmin_fs_t*
+GarminGPIFormat::gpi_gmsd_init(Waypoint* wpt)
 {
   garmin_fs_t* gmsd = garmin_fs_t::find(wpt);
   if (wpt == nullptr) {
@@ -257,14 +113,8 @@ gpi_gmsd_init(Waypoint* wpt)
   return gmsd;
 }
 
-struct lc_string {
-  QByteArray lc;
-  QByteArray str;
-  int strlen{0};
-};
-
-static lc_string
-gpi_read_lc_string()
+GarminGPIFormat::lc_string
+GarminGPIFormat::gpi_read_lc_string() const
 {
   lc_string result;
 
@@ -287,8 +137,8 @@ gpi_read_lc_string()
 }
 
 /* read a standard string with or without 'EN' (or whatever) header */
-static QString
-gpi_read_string(const char* field)
+QString
+GarminGPIFormat::gpi_read_string(const char* field) const
 {
   QByteArray string;
 
@@ -337,8 +187,8 @@ gpi_read_string(const char* field)
   return result;
 }
 
-static void
-read_header()
+void
+GarminGPIFormat::read_header()
 {
   int len, i;
 #ifdef GPI_DBG
@@ -408,13 +258,9 @@ read_header()
 #endif
 }
 
-/* gpi tag handler */
-static int read_tag(const char* caller, int tag, Waypoint* wpt);
-
-
 /* read a single poi with all options */
-static void
-read_poi(const int sz, const int tag)
+void
+GarminGPIFormat::read_poi(const int sz, const int tag)
 {
 #ifdef GPI_DBG
   PP;
@@ -464,8 +310,8 @@ read_poi(const int sz, const int tag)
 }
 
 /* read poi's following a group header */
-static void
-read_poi_list(const int sz)
+void
+GarminGPIFormat::read_poi_list(const int sz)
 {
   int i;
 
@@ -504,9 +350,8 @@ read_poi_list(const int sz)
 #endif
 }
 
-
-static void
-read_poi_group(const int sz, const int tag)
+void
+GarminGPIFormat::read_poi_group(const int sz, const int tag)
 {
   int pos = gbftell(fin);
 #ifdef GPI_DBG
@@ -544,8 +389,8 @@ read_poi_group(const int sz, const int tag)
 // of bytes for all record fields and all nested records, starting after the
 // length field)
 /* gpi tag handler */
-static int
-read_tag(const char* caller, const int tag, Waypoint* wpt)
+int
+GarminGPIFormat::read_tag(const char* caller, const int tag, Waypoint* wpt)
 {
   Q_UNUSED(caller);
   int dist;
@@ -753,8 +598,8 @@ read_tag(const char* caller, const int tag, Waypoint* wpt)
 * %%%                             gpi writer                               %%% *
 *******************************************************************************/
 
-static void
-write_string(const char* str, const char long_format)
+void
+GarminGPIFormat::write_string(const char* str, const char long_format) const
 {
   int len = strlen(str);
   if (long_format) {
@@ -765,20 +610,20 @@ write_string(const char* str, const char long_format)
   gbfwrite(str, 1, len, fout);
 }
 
-static bool
-compare_wpt_cb(const Waypoint* a, const Waypoint* b)
+bool
+GarminGPIFormat::compare_wpt_cb(const Waypoint* a, const Waypoint* b)
 {
   return a->shortname < b->shortname;
 }
 
-static char
-compare_strings(const QString& s1, const QString& s2)
+char
+GarminGPIFormat::compare_strings(const QString& s1, const QString& s2)
 {
   return s1.compare(s2);
 }
 
-static writer_data_t*
-wdata_alloc()
+GarminGPIFormat::writer_data_t*
+GarminGPIFormat::wdata_alloc()
 {
   auto* res = new writer_data_t;
   waypt_init_bounds(&res->bds);
@@ -786,9 +631,8 @@ wdata_alloc()
   return res;
 }
 
-
-static void
-wdata_free(writer_data_t* data)
+void
+GarminGPIFormat::wdata_free(writer_data_t* data)
 {
   foreach (Waypoint* wpt, data->waypt_list) {
 
@@ -815,17 +659,15 @@ wdata_free(writer_data_t* data)
   delete data;
 }
 
-
-static void
-wdata_add_wpt(writer_data_t* data, Waypoint* wpt)
+void
+GarminGPIFormat::wdata_add_wpt(writer_data_t* data, Waypoint* wpt)
 {
   data->waypt_list.append(wpt);
   waypt_add_to_bounds(&data->bds, wpt);
 }
 
-
-static void
-wdata_check(writer_data_t* data)
+void
+GarminGPIFormat::wdata_check(writer_data_t* data) const
 {
   double center_lon;
 
@@ -888,9 +730,8 @@ wdata_check(writer_data_t* data)
   }
 }
 
-
-static int
-wdata_compute_size(writer_data_t* data)
+int
+GarminGPIFormat::wdata_compute_size(writer_data_t* data) const
 {
   int res = 0;
 
@@ -1032,9 +873,8 @@ skip_empty_block:
   return res + 12;     /* + 12 = caller needs info about tag header size */
 }
 
-
-static void
-wdata_write(const writer_data_t* data)
+void
+GarminGPIFormat::wdata_write(const writer_data_t* data) const
 {
   if (data->waypt_list.isEmpty()) {
     goto skip_empty_block;  /* do not issue an empty block */
@@ -1176,9 +1016,8 @@ skip_empty_block:
   }
 }
 
-
-static void
-write_category(const char*, const unsigned char* image, const int image_sz)
+void
+GarminGPIFormat::write_category(const char* /*unused*/, const unsigned char* image, const int image_sz) const
 {
   int sz = wdata_compute_size(wdata);
   sz += 8;     /* string header */
@@ -1202,9 +1041,8 @@ write_category(const char*, const unsigned char* image, const int image_sz)
   }
 }
 
-
-static void
-write_header()
+void
+GarminGPIFormat::write_header() const
 {
   time_t time = gpi_timestamp;
 
@@ -1234,9 +1072,8 @@ write_header()
   gbfputint16(0, fout);
 }
 
-
-static void
-enum_waypt_cb(const Waypoint* ref)
+void
+GarminGPIFormat::enum_waypt_cb(const Waypoint* ref) const
 {
   foreach (const Waypoint* cmp, wdata->waypt_list) {
 
@@ -1259,9 +1096,8 @@ enum_waypt_cb(const Waypoint* ref)
   wdata_add_wpt(wdata, wpt);
 }
 
-
-static void
-load_bitmap_from_file(const char* fname, unsigned char** data, int* data_sz)
+void
+GarminGPIFormat::load_bitmap_from_file(const char* fname, const unsigned char** data, int* data_sz)
 {
   int i, sz;
   int dest_bpp;
@@ -1423,8 +1259,8 @@ load_bitmap_from_file(const char* fname, unsigned char** data, int* data_sz)
 * %%%        global callbacks called by gpsbabel main process              %%% *
 *******************************************************************************/
 
-static void
-garmin_gpi_rd_init(const QString& fname)
+void
+GarminGPIFormat::rd_init(const QString& fname)
 {
   fin = gbfopen_le(fname, "rb", MYNAME);
   rdata = new reader_data_t;
@@ -1446,9 +1282,8 @@ garmin_gpi_rd_init(const QString& fname)
   }
 }
 
-
-static void
-garmin_gpi_wr_init(const QString& fname)
+void
+GarminGPIFormat::wr_init(const QString& fname)
 {
   if ((gpi_timestamp != 0) && !gpsbabel_testmode()) {                  /* not the first gpi output session */
     time_t t = time(nullptr);
@@ -1525,17 +1360,15 @@ garmin_gpi_wr_init(const QString& fname)
   wdata = wdata_alloc();
 }
 
-
-static void
-garmin_gpi_rd_deinit()
+void
+GarminGPIFormat::rd_deinit()
 {
   delete rdata;
   gbfclose(fin);
 }
 
-
-static void
-garmin_gpi_wr_deinit()
+void
+GarminGPIFormat::wr_deinit()
 {
   wdata_free(wdata);
   mkshort_del_handle(&short_h);
@@ -1553,9 +1386,8 @@ garmin_gpi_wr_deinit()
   }
 }
 
-
-static void
-garmin_gpi_read()
+void
+GarminGPIFormat::read()
 {
   while (true) {
     int tag = gbfgetint32(fin);
@@ -1568,11 +1400,10 @@ garmin_gpi_read()
   }
 }
 
-
-static void
-garmin_gpi_write()
+void
+GarminGPIFormat::write()
 {
-  unsigned char* image;
+  const unsigned char* image;
   int image_sz;
 
   if (strlen(opt_cat) == 0) {
@@ -1588,7 +1419,10 @@ garmin_gpi_write()
     image = gpi_bitmap;        /* embedded GPSBabel icon in gpi format */
     image_sz = GPI_BITMAP_SIZE;
   }
-  waypt_disp_all(enum_waypt_cb);
+  auto enum_waypt_cb_lambda = [this](const Waypoint* waypointp)->void {
+    enum_waypt_cb(waypointp);
+  };
+  waypt_disp_all(enum_waypt_cb_lambda);
 
   wdata_check(wdata);
   write_header();
@@ -1601,27 +1435,3 @@ garmin_gpi_write()
     xfree(image);
   }
 }
-
-/**************************************************************************/
-
-ff_vecs_t garmin_gpi_vecs = {
-  ff_type_file,
-  {
-    (ff_cap)(ff_cap_read | ff_cap_write)       /* waypoints */,
-    ff_cap_none                        /* tracks */,
-    ff_cap_none                        /* routes */
-  },
-  garmin_gpi_rd_init,
-  garmin_gpi_wr_init,
-  garmin_gpi_rd_deinit,
-  garmin_gpi_wr_deinit,
-  garmin_gpi_read,
-  garmin_gpi_write,
-  nullptr,
-  &garmin_gpi_args,
-  CET_CHARSET_MS_ANSI, 0               /* WIN-CP1252 */
-  , NULL_POS_OPS,
-  nullptr
-};
-
-/**************************************************************************/
index 4e2b11f0b0355312f5ded674fb0818dce7466849..7457b70bda4a15a97d518f1756ec020cef44328f 100644 (file)
-#ifndef GARMIN_GPI_H
-#define GARMIN_GPI_H
-
-static unsigned char gpi_bitmap[] = {
-  0x00,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x08,0x00,0x00,0x00,0x40,0x02,0x00,0x00,
-  0x2c,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0xff,0x00,0xff,0x00,0x01,0x00,0x00,0x00,
-  0x6c,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7f,0x00,0x7e,0x7e,0x7e,
-  0x7e,0x7e,0x7e,0x7e,0x7e,0x7e,0x7e,0x7e,0x7e,0x7e,0x7e,0x7e,0x7e,0x7e,0x7e,0x7e,
-  0x7e,0x7e,0x00,0x7e,0x00,0x7e,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,
-  0x7f,0x7f,0x59,0x67,0x65,0x7f,0x7f,0x7f,0x7f,0x7f,0x00,0x7e,0x00,0x7e,0x7f,0x7f,
-  0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x74,0x3d,0x42,0x56,0x7e,0x7e,0x7f,
-  0x7f,0x7f,0x00,0x7e,0x00,0x7e,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,
-  0x7f,0x72,0x38,0x49,0x47,0x7e,0x7e,0x7f,0x7f,0x7f,0x00,0x7e,0x00,0x7e,0x7f,0x7f,
-  0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7d,0x37,0x47,0x7d,0x7e,0x7e,0x7f,
-  0x7f,0x7f,0x00,0x7e,0x00,0x7e,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,
-  0x7f,0x7d,0x37,0x47,0x7d,0x7e,0x7e,0x7f,0x7f,0x7f,0x00,0x7e,0x00,0x7e,0x7f,0x7f,
-  0x7f,0x7f,0x7f,0x7f,0x7f,0x7c,0x6c,0x50,0x44,0x5e,0x4f,0x76,0x7e,0x7f,0x7f,0x7f,
-  0x7f,0x7f,0x00,0x7e,0x00,0x7e,0x7f,0x77,0x7e,0x7f,0x7f,0x7e,0x62,0x0d,0x00,0x05,
-  0x10,0x08,0x09,0x59,0x7e,0x7e,0x7e,0x7f,0x7f,0x7f,0x00,0x7e,0x00,0x7e,0x29,0x1c,
-  0x4c,0x7f,0x7f,0x60,0x02,0x0c,0x2a,0x37,0x51,0x63,0x57,0x15,0x58,0x7e,0x7e,0x7f,
-  0x7f,0x7f,0x00,0x7e,0x00,0x7e,0x68,0x5a,0x41,0x5f,0x5f,0x07,0x0e,0x3d,0x41,0x41,
-  0x4d,0x55,0x6b,0x61,0x26,0x57,0x57,0x2b,0x2f,0x30,0x00,0x7e,0x00,0x7e,0x77,0x7d,
-  0x4e,0x3d,0x3d,0x16,0x35,0x41,0x7d,0x49,0x18,0x48,0x52,0x54,0x5b,0x31,0x31,0x63,
-  0x7f,0x7f,0x00,0x7e,0x00,0x7e,0x40,0x7d,0x75,0x47,0x47,0x41,0x35,0x40,0x72,0x1e,
-  0x7c,0x5d,0x1d,0x20,0x49,0x3d,0x3d,0x5b,0x7f,0x7f,0x00,0x7e,0x00,0x7e,0x60,0x5c,
-  0x7a,0x1a,0x1a,0x3b,0x38,0x5d,0x0e,0x59,0x7d,0x3c,0x72,0x37,0x78,0x60,0x60,0x28,
-  0x4f,0x71,0x00,0x7e,0x00,0x7e,0x7e,0x43,0x33,0x69,0x69,0x17,0x22,0x7d,0x2c,0x27,
-  0x2a,0x2b,0x7d,0x32,0x61,0x4f,0x4f,0x36,0x3f,0x4c,0x00,0x7e,0x00,0x7e,0x7f,0x7e,
-  0x3a,0x2b,0x2b,0x45,0x1a,0x40,0x47,0x7d,0x37,0x41,0x12,0x25,0x5e,0x46,0x46,0x4d,
-  0x62,0x53,0x00,0x7e,0x00,0x7e,0x7f,0x7e,0x73,0x71,0x71,0x6a,0x13,0x39,0x1b,0x45,
-  0x62,0x50,0x3a,0x7e,0x7e,0x7b,0x7b,0x5c,0x5b,0x49,0x00,0x7e,0x00,0x7e,0x7f,0x7e,
-  0x59,0x01,0x01,0x06,0x64,0x35,0x4e,0x3e,0x26,0x21,0x66,0x7f,0x45,0x04,0x04,0x11,
-  0x7f,0x7f,0x00,0x7e,0x00,0x7e,0x7f,0x7e,0x59,0x01,0x01,0x06,0x64,0x35,0x4e,0x3e,
-  0x26,0x21,0x66,0x7f,0x45,0x04,0x04,0x11,0x7f,0x7f,0x00,0x7e,0x00,0x7e,0x7f,0x7e,
-  0x7c,0x0a,0x0a,0x0f,0x65,0x7d,0x74,0x71,0x7c,0x7e,0x7e,0x7e,0x58,0x03,0x03,0x2b,
-  0x7f,0x7f,0x00,0x7e,0x00,0x7e,0x7f,0x7f,0x7f,0x6d,0x6d,0x6f,0x2d,0x1d,0x63,0x7a,
-  0x7e,0x75,0x5d,0x19,0x32,0x70,0x70,0x6f,0x7f,0x7f,0x00,0x7e,0x00,0x7e,0x7f,0x7f,
-  0x7f,0x7f,0x7f,0x7e,0x7d,0x53,0x35,0x0b,0x1f,0x0e,0x34,0x5a,0x7f,0x7f,0x7f,0x7f,
-  0x7f,0x7f,0x00,0x7e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7e,0x7f,0x7e,0x7e,0x7e,
-  0x7e,0x7e,0x7e,0x7e,0x7e,0x7e,0x7e,0x7e,0x7e,0x7e,0x7e,0x7e,0x7e,0x7e,0x7e,0x7e,
-  0x7e,0x7e,0x7e,0x7e,0x0a,0x0a,0x0a,0x00,0x0b,0x0b,0x0b,0x00,0x16,0x16,0x16,0x00,
-  0x1f,0x1f,0x1f,0x00,0x28,0x28,0x28,0x00,0x2d,0x2d,0x2d,0x00,0x35,0x35,0x35,0x00,
-  0x3d,0x3d,0x3d,0x00,0x40,0x40,0x40,0x00,0x41,0x41,0x41,0x00,0x43,0x43,0x43,0x00,
-  0x46,0x46,0x46,0x00,0x47,0x47,0x47,0x00,0x4b,0x4b,0x4b,0x00,0x4e,0x4e,0x4e,0x00,
-  0x53,0x53,0x53,0x00,0x54,0x54,0x54,0x00,0x56,0x56,0x56,0x00,0x59,0x59,0x59,0x00,
-  0x5a,0x5a,0x5a,0x00,0x5f,0x5f,0x5f,0x00,0x60,0x60,0x60,0x00,0x62,0x62,0x62,0x00,
-  0x63,0x63,0x63,0x00,0x6a,0x6a,0x6a,0x00,0x74,0x74,0x74,0x00,0x75,0x75,0x75,0x00,
-  0x76,0x76,0x76,0x00,0x78,0x78,0x78,0x00,0x79,0x79,0x79,0x00,0x7a,0x7a,0x7a,0x00,
-  0x7c,0x7c,0x7c,0x00,0x7d,0x7d,0x7d,0x00,0x7e,0x7e,0x7e,0x00,0x80,0x80,0x80,0x00,
-  0x81,0x81,0x81,0x00,0x82,0x82,0x82,0x00,0x83,0x83,0x83,0x00,0x84,0x84,0x84,0x00,
-  0x85,0x85,0x85,0x00,0x87,0x87,0x87,0x00,0x88,0x88,0x88,0x00,0x89,0x89,0x89,0x00,
-  0x8a,0x8a,0x8a,0x00,0x8b,0x8b,0x8b,0x00,0x8e,0x8e,0x8e,0x00,0x90,0x90,0x90,0x00,
-  0x91,0x91,0x91,0x00,0x92,0x92,0x92,0x00,0x94,0x94,0x94,0x00,0x95,0x95,0x95,0x00,
-  0x96,0x96,0x96,0x00,0x97,0x97,0x97,0x00,0x98,0x98,0x98,0x00,0x9b,0x9b,0x9b,0x00,
-  0x9c,0x9c,0x9c,0x00,0x9d,0x9d,0x9d,0x00,0xa0,0xa0,0xa0,0x00,0xa1,0xa1,0xa1,0x00,
-  0xa2,0xa2,0xa2,0x00,0xa4,0xa4,0xa4,0x00,0xa6,0xa6,0xa6,0x00,0xa7,0xa7,0xa7,0x00,
-  0xab,0xab,0xab,0x00,0xac,0xac,0xac,0x00,0xad,0xad,0xad,0x00,0xae,0xae,0xae,0x00,
-  0xaf,0xaf,0xaf,0x00,0xb0,0xb0,0xb0,0x00,0xb1,0xb1,0xb1,0x00,0xb2,0xb2,0xb2,0x00,
-  0xb3,0xb3,0xb3,0x00,0xb4,0xb4,0xb4,0x00,0xb5,0xb5,0xb5,0x00,0xb6,0xb6,0xb6,0x00,
-  0xb7,0xb7,0xb7,0x00,0xb9,0xb9,0xb9,0x00,0xbb,0xbb,0xbb,0x00,0xbc,0xbc,0xbc,0x00,
-  0xbe,0xbe,0xbe,0x00,0xbf,0xbf,0xbf,0x00,0xc0,0xc0,0xc0,0x00,0xc1,0xc1,0xc1,0x00,
-  0xc2,0xc2,0xc2,0x00,0xc3,0xc3,0xc3,0x00,0xc4,0xc4,0xc4,0x00,0xc5,0xc5,0xc5,0x00,
-  0xc9,0xc9,0xc9,0x00,0xcb,0xcb,0xcb,0x00,0xcc,0xcc,0xcc,0x00,0xce,0xce,0xce,0x00,
-  0xcf,0xcf,0xcf,0x00,0xd0,0xd0,0xd0,0x00,0xd1,0xd1,0xd1,0x00,0xd2,0xd2,0xd2,0x00,
-  0xd4,0xd4,0xd4,0x00,0xd5,0xd5,0xd5,0x00,0xd6,0xd6,0xd6,0x00,0xd9,0xd9,0xd9,0x00,
-  0xda,0xda,0xda,0x00,0xdb,0xdb,0xdb,0x00,0xdc,0xdc,0xdc,0x00,0xdd,0xdd,0xdd,0x00,
-  0xe0,0xe0,0xe0,0x00,0xe1,0xe1,0xe1,0x00,0xe2,0xe2,0xe2,0x00,0xe3,0xe3,0xe3,0x00,
-  0xe4,0xe4,0xe4,0x00,0xe6,0xe6,0xe6,0x00,0xe8,0xe8,0xe8,0x00,0xe9,0xe9,0xe9,0x00,
-  0xea,0xea,0xea,0x00,0xeb,0xeb,0xeb,0x00,0xec,0xec,0xec,0x00,0xed,0xed,0xed,0x00,
-  0xee,0xee,0xee,0x00,0xf0,0xf0,0xf0,0x00,0xf3,0xf3,0xf3,0x00,0xf4,0xf4,0xf4,0x00,
-  0xf5,0xf5,0xf5,0x00,0xf7,0xf7,0xf7,0x00,0xf8,0xf8,0xf8,0x00,0xf9,0xf9,0xf9,0x00,
-  0xfa,0xfa,0xfa,0x00,0xfb,0xfb,0xfb,0x00,0xfc,0xfc,0xfc,0x00,0xff,0xff,0xff,0x00,
-  0xff,0x00,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-  0x00,0x00,0x00,0x00
-};
+/*
+
+    Support for Garmin Points of Interest (.gpi files)
+
+    Copyright (C) 2007 Olaf Klein, o.b.klein@gpsbabel.org
+    Copyright (C) 2007-2012 Robert Lipe, robertlipe+source@gpsbabel.org
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+
+ */
+#ifndef GARMIN_GPI_H_INCLUDED_
+#define GARMIN_GPI_H_INCLUDED_
+
+/*
+       History:
+
+       * 2007/05/18: initial release (only a reader)
+       * 2007/05/20: added writer code with embedded bitmap
+       * 2007/05/22: add support for multiple bounding boxes
+                     (useful / required!) for large waypoints lists
+       * 2007/05/23: add optional user bitmap
+       * 2007/06/02: new method to compute center (mean) of bounds
+                     avoid endless loop in group splitting
+       * 2007/07/10: put address fields (i.e. city) into GMSD
+       * 2007/07/12: add write support for new address fields
+       * 2007/10/20: add option unique
+       * 2007/12/02: support speed and proximity distance (+ alerts)
+       * 2008/01/14: fix structure error after adding speed/proximity
+       * 2008/03/22: add options "speed" and "proximity" (default values) and "sleep"
+
+       ToDo:
+
+       * Display mode ("Symbol & Name") ??? not in gpi ???
+       * support category from GMSD "Garmin Special Data"
+*/
+
+#include <QByteArray>   // for QByteArray
+#include <QList>        // for QList
+#include <QString>      // for QString
+#include <QVector>      // for QVector
+
+#include <cstdint>      // for int32_t, int16_t, uint16_t
+#include <ctime>        // for time_t
+
+#include "defs.h"       // for arglist_t, ARG_NOMINMAX, ff_cap, Waypoint, ARGTYPE_BOOL, ARGTYPE_STRING, ff_cap_none, ARGTYPE_FILE, ARGTYPE_INT, CET_CHARSET_MS_ANSI, bounds, ff_cap_read, ff_cap_write, ff_type, ff_type_file, short_handle
+#include "format.h"     // for Format
+#include "garmin_fs.h"  // for garmin_fs_t
+#include "garmin_gpi.h"  // lines 66-66
+#include "gbfile.h"     // for gbfile
+
+
+class GarminGPIFormat : public Format
+{
+public:
+  QVector<arglist_t>* get_args() override
+  {
+    return &garmin_gpi_args;
+  }
+
+  ff_type get_type() const override
+  {
+    return ff_type_file;
+  }
+
+  QVector<ff_cap> get_cap() const override
+  {
+    return {
+      (ff_cap)(ff_cap_read | ff_cap_write)     /* waypoints */,
+      ff_cap_none                      /* tracks */,
+      ff_cap_none                      /* routes */
+    };
+  }
+
+  QString get_encode() const override
+  {
+    return CET_CHARSET_MS_ANSI;    /* WIN-CP1252 */
+  }
 
-#define GPI_BITMAP_SIZE sizeof(gpi_bitmap)
+  int get_fixed_encode() const override
+  {
+    return 0;
+  }
+
+  void rd_init(const QString& fname) override;
+  void read() override;
+  void rd_deinit() override;
+  void wr_init(const QString& fname) override;
+  void write() override;
+  void wr_deinit() override;
+
+private:
+  /* Types */
+
+  struct reader_data_t {
+    int D2{};
+    char S3[9]{};              /* "GRMRECnn" */
+    time_t crdate{};   /* creation date and time */
+    char POI[4]{};             /* "POI" */
+    char S8[3]{};
+    QString group;
+    QString category;
+  };
+
+  struct writer_data_t {
+    QList<Waypoint*> waypt_list;
+    int sz{0};
+    int alert{0};
+    bounds bds{};
+    writer_data_t* top_left{nullptr};
+    writer_data_t* top_right{nullptr};
+    writer_data_t* bottom_left{nullptr};
+    writer_data_t* bottom_right{nullptr};
+  };
+
+  struct gpi_waypt_data_t {
+    int sz;
+    char* addr;
+    char* postal_code;
+  };
+
+  struct bmp_header_t {
+    int32_t size;
+    int16_t res1;
+    int16_t res2;
+    int32_t image_offset;
+    int32_t header_size;
+    int32_t width;
+    int32_t height;
+    int16_t planes;
+    int16_t bpp;
+    int32_t compression_type;
+    int32_t image_data_size;
+    int32_t resolution_h;
+    int32_t resolution_v;
+    int32_t used_colors;
+    int32_t important_colors;
+  };
+
+  struct gpi_bitmap_header_t {
+    int16_t index;
+    int16_t height;
+    int16_t width;
+    int16_t line_sz;
+    int16_t bpp;
+    int16_t fixed_0;
+    int32_t image_size;
+    int32_t fixed_2c;
+    int32_t palette_size;
+    int32_t tr_color;
+    int32_t flag2;
+    int32_t size_2c;
+  };
+
+  struct gpi_waypt_t {
+    int sz{0};
+    int alerts{0};
+    short mask{0};
+    QString addr;
+    QString city;
+    QString country;
+    QString phone_nr;
+    QString postal_code;
+    QString state;
+  };
+
+  struct lc_string {
+    QByteArray lc;
+    QByteArray str;
+    int strlen{0};
+  };
+
+  /* Constants */
+  static constexpr unsigned char gpi_bitmap[] = {
+    0x00,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x08,0x00,0x00,0x00,0x40,0x02,0x00,0x00,
+    0x2c,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0xff,0x00,0xff,0x00,0x01,0x00,0x00,0x00,
+    0x6c,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7f,0x00,0x7e,0x7e,0x7e,
+    0x7e,0x7e,0x7e,0x7e,0x7e,0x7e,0x7e,0x7e,0x7e,0x7e,0x7e,0x7e,0x7e,0x7e,0x7e,0x7e,
+    0x7e,0x7e,0x00,0x7e,0x00,0x7e,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,
+    0x7f,0x7f,0x59,0x67,0x65,0x7f,0x7f,0x7f,0x7f,0x7f,0x00,0x7e,0x00,0x7e,0x7f,0x7f,
+    0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x74,0x3d,0x42,0x56,0x7e,0x7e,0x7f,
+    0x7f,0x7f,0x00,0x7e,0x00,0x7e,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,
+    0x7f,0x72,0x38,0x49,0x47,0x7e,0x7e,0x7f,0x7f,0x7f,0x00,0x7e,0x00,0x7e,0x7f,0x7f,
+    0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7d,0x37,0x47,0x7d,0x7e,0x7e,0x7f,
+    0x7f,0x7f,0x00,0x7e,0x00,0x7e,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,
+    0x7f,0x7d,0x37,0x47,0x7d,0x7e,0x7e,0x7f,0x7f,0x7f,0x00,0x7e,0x00,0x7e,0x7f,0x7f,
+    0x7f,0x7f,0x7f,0x7f,0x7f,0x7c,0x6c,0x50,0x44,0x5e,0x4f,0x76,0x7e,0x7f,0x7f,0x7f,
+    0x7f,0x7f,0x00,0x7e,0x00,0x7e,0x7f,0x77,0x7e,0x7f,0x7f,0x7e,0x62,0x0d,0x00,0x05,
+    0x10,0x08,0x09,0x59,0x7e,0x7e,0x7e,0x7f,0x7f,0x7f,0x00,0x7e,0x00,0x7e,0x29,0x1c,
+    0x4c,0x7f,0x7f,0x60,0x02,0x0c,0x2a,0x37,0x51,0x63,0x57,0x15,0x58,0x7e,0x7e,0x7f,
+    0x7f,0x7f,0x00,0x7e,0x00,0x7e,0x68,0x5a,0x41,0x5f,0x5f,0x07,0x0e,0x3d,0x41,0x41,
+    0x4d,0x55,0x6b,0x61,0x26,0x57,0x57,0x2b,0x2f,0x30,0x00,0x7e,0x00,0x7e,0x77,0x7d,
+    0x4e,0x3d,0x3d,0x16,0x35,0x41,0x7d,0x49,0x18,0x48,0x52,0x54,0x5b,0x31,0x31,0x63,
+    0x7f,0x7f,0x00,0x7e,0x00,0x7e,0x40,0x7d,0x75,0x47,0x47,0x41,0x35,0x40,0x72,0x1e,
+    0x7c,0x5d,0x1d,0x20,0x49,0x3d,0x3d,0x5b,0x7f,0x7f,0x00,0x7e,0x00,0x7e,0x60,0x5c,
+    0x7a,0x1a,0x1a,0x3b,0x38,0x5d,0x0e,0x59,0x7d,0x3c,0x72,0x37,0x78,0x60,0x60,0x28,
+    0x4f,0x71,0x00,0x7e,0x00,0x7e,0x7e,0x43,0x33,0x69,0x69,0x17,0x22,0x7d,0x2c,0x27,
+    0x2a,0x2b,0x7d,0x32,0x61,0x4f,0x4f,0x36,0x3f,0x4c,0x00,0x7e,0x00,0x7e,0x7f,0x7e,
+    0x3a,0x2b,0x2b,0x45,0x1a,0x40,0x47,0x7d,0x37,0x41,0x12,0x25,0x5e,0x46,0x46,0x4d,
+    0x62,0x53,0x00,0x7e,0x00,0x7e,0x7f,0x7e,0x73,0x71,0x71,0x6a,0x13,0x39,0x1b,0x45,
+    0x62,0x50,0x3a,0x7e,0x7e,0x7b,0x7b,0x5c,0x5b,0x49,0x00,0x7e,0x00,0x7e,0x7f,0x7e,
+    0x59,0x01,0x01,0x06,0x64,0x35,0x4e,0x3e,0x26,0x21,0x66,0x7f,0x45,0x04,0x04,0x11,
+    0x7f,0x7f,0x00,0x7e,0x00,0x7e,0x7f,0x7e,0x59,0x01,0x01,0x06,0x64,0x35,0x4e,0x3e,
+    0x26,0x21,0x66,0x7f,0x45,0x04,0x04,0x11,0x7f,0x7f,0x00,0x7e,0x00,0x7e,0x7f,0x7e,
+    0x7c,0x0a,0x0a,0x0f,0x65,0x7d,0x74,0x71,0x7c,0x7e,0x7e,0x7e,0x58,0x03,0x03,0x2b,
+    0x7f,0x7f,0x00,0x7e,0x00,0x7e,0x7f,0x7f,0x7f,0x6d,0x6d,0x6f,0x2d,0x1d,0x63,0x7a,
+    0x7e,0x75,0x5d,0x19,0x32,0x70,0x70,0x6f,0x7f,0x7f,0x00,0x7e,0x00,0x7e,0x7f,0x7f,
+    0x7f,0x7f,0x7f,0x7e,0x7d,0x53,0x35,0x0b,0x1f,0x0e,0x34,0x5a,0x7f,0x7f,0x7f,0x7f,
+    0x7f,0x7f,0x00,0x7e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7e,0x7f,0x7e,0x7e,0x7e,
+    0x7e,0x7e,0x7e,0x7e,0x7e,0x7e,0x7e,0x7e,0x7e,0x7e,0x7e,0x7e,0x7e,0x7e,0x7e,0x7e,
+    0x7e,0x7e,0x7e,0x7e,0x0a,0x0a,0x0a,0x00,0x0b,0x0b,0x0b,0x00,0x16,0x16,0x16,0x00,
+    0x1f,0x1f,0x1f,0x00,0x28,0x28,0x28,0x00,0x2d,0x2d,0x2d,0x00,0x35,0x35,0x35,0x00,
+    0x3d,0x3d,0x3d,0x00,0x40,0x40,0x40,0x00,0x41,0x41,0x41,0x00,0x43,0x43,0x43,0x00,
+    0x46,0x46,0x46,0x00,0x47,0x47,0x47,0x00,0x4b,0x4b,0x4b,0x00,0x4e,0x4e,0x4e,0x00,
+    0x53,0x53,0x53,0x00,0x54,0x54,0x54,0x00,0x56,0x56,0x56,0x00,0x59,0x59,0x59,0x00,
+    0x5a,0x5a,0x5a,0x00,0x5f,0x5f,0x5f,0x00,0x60,0x60,0x60,0x00,0x62,0x62,0x62,0x00,
+    0x63,0x63,0x63,0x00,0x6a,0x6a,0x6a,0x00,0x74,0x74,0x74,0x00,0x75,0x75,0x75,0x00,
+    0x76,0x76,0x76,0x00,0x78,0x78,0x78,0x00,0x79,0x79,0x79,0x00,0x7a,0x7a,0x7a,0x00,
+    0x7c,0x7c,0x7c,0x00,0x7d,0x7d,0x7d,0x00,0x7e,0x7e,0x7e,0x00,0x80,0x80,0x80,0x00,
+    0x81,0x81,0x81,0x00,0x82,0x82,0x82,0x00,0x83,0x83,0x83,0x00,0x84,0x84,0x84,0x00,
+    0x85,0x85,0x85,0x00,0x87,0x87,0x87,0x00,0x88,0x88,0x88,0x00,0x89,0x89,0x89,0x00,
+    0x8a,0x8a,0x8a,0x00,0x8b,0x8b,0x8b,0x00,0x8e,0x8e,0x8e,0x00,0x90,0x90,0x90,0x00,
+    0x91,0x91,0x91,0x00,0x92,0x92,0x92,0x00,0x94,0x94,0x94,0x00,0x95,0x95,0x95,0x00,
+    0x96,0x96,0x96,0x00,0x97,0x97,0x97,0x00,0x98,0x98,0x98,0x00,0x9b,0x9b,0x9b,0x00,
+    0x9c,0x9c,0x9c,0x00,0x9d,0x9d,0x9d,0x00,0xa0,0xa0,0xa0,0x00,0xa1,0xa1,0xa1,0x00,
+    0xa2,0xa2,0xa2,0x00,0xa4,0xa4,0xa4,0x00,0xa6,0xa6,0xa6,0x00,0xa7,0xa7,0xa7,0x00,
+    0xab,0xab,0xab,0x00,0xac,0xac,0xac,0x00,0xad,0xad,0xad,0x00,0xae,0xae,0xae,0x00,
+    0xaf,0xaf,0xaf,0x00,0xb0,0xb0,0xb0,0x00,0xb1,0xb1,0xb1,0x00,0xb2,0xb2,0xb2,0x00,
+    0xb3,0xb3,0xb3,0x00,0xb4,0xb4,0xb4,0x00,0xb5,0xb5,0xb5,0x00,0xb6,0xb6,0xb6,0x00,
+    0xb7,0xb7,0xb7,0x00,0xb9,0xb9,0xb9,0x00,0xbb,0xbb,0xbb,0x00,0xbc,0xbc,0xbc,0x00,
+    0xbe,0xbe,0xbe,0x00,0xbf,0xbf,0xbf,0x00,0xc0,0xc0,0xc0,0x00,0xc1,0xc1,0xc1,0x00,
+    0xc2,0xc2,0xc2,0x00,0xc3,0xc3,0xc3,0x00,0xc4,0xc4,0xc4,0x00,0xc5,0xc5,0xc5,0x00,
+    0xc9,0xc9,0xc9,0x00,0xcb,0xcb,0xcb,0x00,0xcc,0xcc,0xcc,0x00,0xce,0xce,0xce,0x00,
+    0xcf,0xcf,0xcf,0x00,0xd0,0xd0,0xd0,0x00,0xd1,0xd1,0xd1,0x00,0xd2,0xd2,0xd2,0x00,
+    0xd4,0xd4,0xd4,0x00,0xd5,0xd5,0xd5,0x00,0xd6,0xd6,0xd6,0x00,0xd9,0xd9,0xd9,0x00,
+    0xda,0xda,0xda,0x00,0xdb,0xdb,0xdb,0x00,0xdc,0xdc,0xdc,0x00,0xdd,0xdd,0xdd,0x00,
+    0xe0,0xe0,0xe0,0x00,0xe1,0xe1,0xe1,0x00,0xe2,0xe2,0xe2,0x00,0xe3,0xe3,0xe3,0x00,
+    0xe4,0xe4,0xe4,0x00,0xe6,0xe6,0xe6,0x00,0xe8,0xe8,0xe8,0x00,0xe9,0xe9,0xe9,0x00,
+    0xea,0xea,0xea,0x00,0xeb,0xeb,0xeb,0x00,0xec,0xec,0xec,0x00,0xed,0xed,0xed,0x00,
+    0xee,0xee,0xee,0x00,0xf0,0xf0,0xf0,0x00,0xf3,0xf3,0xf3,0x00,0xf4,0xf4,0xf4,0x00,
+    0xf5,0xf5,0xf5,0x00,0xf7,0xf7,0xf7,0x00,0xf8,0xf8,0xf8,0x00,0xf9,0xf9,0xf9,0x00,
+    0xfa,0xfa,0xfa,0x00,0xfb,0xfb,0xfb,0x00,0xfc,0xfc,0xfc,0x00,0xff,0xff,0xff,0x00,
+    0xff,0x00,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00
+  };
+
+  /* Member Functions */
+
+  static garmin_fs_t* gpi_gmsd_init(Waypoint* wpt);
+  lc_string gpi_read_lc_string() const;
+  QString gpi_read_string(const char* field) const;
+  void read_header();
+  void read_poi(int sz, int tag);
+  void read_poi_list(int sz);
+  void read_poi_group(int sz, int tag);
+  int read_tag(const char* caller, int tag, Waypoint* wpt);
+  void write_string(const char* str, char long_format) const;
+  static bool compare_wpt_cb(const Waypoint* a, const Waypoint* b);
+  static char compare_strings(const QString& s1, const QString& s2);
+  static writer_data_t* wdata_alloc();
+  static void wdata_free(GarminGPIFormat::writer_data_t* data);
+  static void wdata_add_wpt(GarminGPIFormat::writer_data_t* data, Waypoint* wpt);
+  void wdata_check(GarminGPIFormat::writer_data_t* data) const;
+  int wdata_compute_size(GarminGPIFormat::writer_data_t* data) const;
+  void wdata_write(const GarminGPIFormat::writer_data_t* data) const;
+  void write_category(const char* unused, const unsigned char* image, int image_sz) const;
+  void write_header() const;
+  void enum_waypt_cb(const Waypoint* ref) const;
+  static void load_bitmap_from_file(const char* fname, const unsigned char** data, int* data_sz);
+
+  /* Data Members */
+
+  char* opt_cat{}, *opt_pos{}, *opt_notes{}, *opt_hide_bitmap{}, *opt_descr{}, *opt_bitmap{};
+  char* opt_unique{}, *opt_alerts{}, *opt_units{}, *opt_speed{}, *opt_proximity{}, *opt_sleep{};
+  char* opt_lang{};
+  char* opt_writecodec{};
+  double defspeed{}, defproximity{};
+  int alerts{};
+
+  QVector<arglist_t> garmin_gpi_args = {
+    {
+      "alerts", &opt_alerts, "Enable alerts on speed or proximity distance",
+      nullptr, ARGTYPE_BOOL, ARG_NOMINMAX, nullptr
+    },
+    {
+      "bitmap", &opt_bitmap, "Use specified bitmap on output",
+      nullptr, ARGTYPE_FILE, ARG_NOMINMAX, nullptr
+    },
+    {
+      "category", &opt_cat, "Default category on output",
+      "My points", ARGTYPE_STRING, ARG_NOMINMAX, nullptr
+    },
+    {
+      "hide", &opt_hide_bitmap, "Don't show gpi bitmap on device",
+      nullptr, ARGTYPE_BOOL, ARG_NOMINMAX, nullptr
+    },
+    {
+      "descr", &opt_descr, "Write description to address field",
+      nullptr, ARGTYPE_BOOL, ARG_NOMINMAX, nullptr
+    },
+    {
+      "notes", &opt_notes, "Write notes to address field",
+      nullptr, ARGTYPE_BOOL, ARG_NOMINMAX, nullptr
+    },
+    {
+      "position", &opt_pos, "Write position to address field",
+      nullptr, ARGTYPE_BOOL, ARG_NOMINMAX, nullptr
+    },
+    {
+      "proximity", &opt_proximity, "Default proximity",
+      nullptr, ARGTYPE_STRING, ARG_NOMINMAX, nullptr
+    },
+    {
+      "sleep", &opt_sleep, "After output job done sleep n second(s)",
+      nullptr, ARGTYPE_INT, "1", nullptr, nullptr
+    },
+    {
+      "speed", &opt_speed, "Default speed",
+      nullptr, ARGTYPE_STRING, ARG_NOMINMAX, nullptr
+    },
+    {
+      "unique", &opt_unique, "Create unique waypoint names (default = yes)",
+      "Y", ARGTYPE_BOOL, ARG_NOMINMAX, nullptr
+    },
+    {
+      "units", &opt_units, "Units used for names with @speed ('s'tatute or 'm'etric)",
+      "m", ARGTYPE_STRING, ARG_NOMINMAX, nullptr
+    },
+    {
+      "writecodec", &opt_writecodec, "codec to use for writing strings",
+      "windows-1252", ARGTYPE_STRING, ARG_NOMINMAX, nullptr
+    },
+    {
+      "languagecode", &opt_lang, "language code to use for reading dual language files",
+      nullptr, ARGTYPE_STRING, ARG_NOMINMAX, nullptr
+    }
+  };
+
+
+  gbfile* fin{}, *fout{};
+  uint16_t codepage{}; /* code-page, e.g. 1252, 65001 */
+  reader_data_t* rdata{};
+  writer_data_t* wdata{};
+  short_handle short_h{};
+  char units{};
+  time_t gpi_timestamp = 0;
+};
 
-#endif
+#endif // GARMIN_GPI_H_INCLUDED_
diff --git a/vecs.h b/vecs.h
index 4f7611c7e98b6261743f6dba7311087d2a2b02a5..b6f315f9ced54f7b13a716091e63d89698461c75 100644 (file)
--- a/vecs.h
+++ b/vecs.h
@@ -34,6 +34,7 @@
 #include "exif.h"
 #include "format.h"
 #include "garmin_fit.h"
+#include "garmin_gpi.h"
 #include "geojson.h"
 #include "ggv_bin.h"
 #include "globalsat_sport.h"
@@ -103,7 +104,6 @@ extern ff_vecs_t garmin_txt_vecs;
 extern ff_vecs_t dmtlog_vecs;
 extern ff_vecs_t raymarine_vecs;
 extern ff_vecs_t ggv_log_vecs;
-extern ff_vecs_t garmin_gpi_vecs;
 extern ff_vecs_t lmx_vecs;
 extern ff_vecs_t xol_vecs;
 extern ff_vecs_t navilink_vecs;
@@ -281,7 +281,7 @@ private:
   LegacyFormat dmtlog_fmt {dmtlog_vecs};
   LegacyFormat raymarine_fmt {raymarine_vecs};
   LegacyFormat ggv_log_fmt {ggv_log_vecs};
-  LegacyFormat garmin_gpi_fmt {garmin_gpi_vecs};
+  GarminGPIFormat garmin_gpi_fmt;
   LegacyFormat lmx_fmt {lmx_vecs};
   RandomFormat random_fmt;
   LegacyFormat xol_fmt {xol_vecs};